撰寫本系列文章目的在於提升資訊安全之實務能力,
並透過實作體悟到資訊安全領域的重要性,
本系列所有文章之內容皆有一定技術水平,
不得從事非法行為、惡意攻擊等非法活動,
「一切不合法規之行為皆受法律所約束」,
為了避免造成公司、廠商或玩家之間困擾,
所有實作不會拿已上市產品、Online Game 等等來作範例學習,
且部分具有深度、價值之內容,將會提升一定閱讀門檻(不對該技術做分析、解說),
請勿透過本系列文章所學,從事任何非法活動,請不要以身試法!!!
就在昨天(鐵人賽 Day 03)的時候有說到 Blackbone 的其中一個 DLL Injection 方法,
還沒看的人可以先去快速看一下:【Day 03】- 打針!打針!從 R0 注入的那件事!
在昨天的文章中,最後部分有提到兩個隱藏 Module 的方法,
而就在今天!就是這篇文章!將要來說說第一個隱藏技術:
PEB(Process Environment Block)斷鏈
另外:
明天,也就是鐵人賽 Day 05 將會介紹 PEB 斷鏈的缺點與找出隱藏 Module 的方法,
後天,也就是鐵人賽 Day 06 將會介紹其它更厲害、更難以偵測的隱藏 Module 方法!
最後:
這個 Module 系列就會在鐵人賽 Day 06 結束,
當然,隱藏 Module 的方法百百種,這幾天只簡單的講幾個例子~
鐵人賽 Day 07 將會進入 Process 偽裝、隱藏,甚至是 Rookit 常用的技術。
(在閱讀這篇文章之前,應該要確保目前腦袋是清晰的)
首先要先說一下,
小弟我目前還屬於菜鳥階段,正不斷努力學習中,
若有發現錯誤或不妥之處還請不吝賜教。
歡迎大家多多留言,互相交流交流。
那麼進入今天主題~~
第一個問題:
什麼是 PEB(Process Environment Block)???
那這個 PEB 長什麼樣子?可以怎麼看?
!process 0 0 notepad.exe
查看 notepad.exe
lkd> !process 0 0 notepad.exe
PROCESS ffff8f899b178080
SessionId: 1 Cid: 0b2c Peb: ecacd59000 ParentCid: 10b8
DirBase: 984ad000 ObjectTable: ffffa685c250d6c0 HandleCount: 262.
Image: notepad.exe
Peb: ecacd59000
!peb ecacd59000
查看 notepad.exe 的 PEB
dt _peb
查看 PEB 結構
lkd> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
+0x010 ImageBaseAddress : Ptr64 Void
+0x018 Ldr : Ptr64 _PEB_LDR_DATA
+0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
+0x3a0 WaitOnAddressHashTable : [128] Ptr64 Void
+0x7a0 TelemetryCoverageHeader : Ptr64 Void
+0x7a8 CloudFileFlags : Uint4B
好了,到這邊基本上介紹完 PEB 是什麼了(? XD 已經快速帶過
假設你/妳剛才有仔細看的話,會注意到:
lkd> !peb ecacd59000
PEB at 000000ecacd59000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: No
--->ImageBaseAddress: 00007ff67a610000
NtGlobalFlag: 0
NtGlobalFlag2: 0
--->Ldr 00007ff9baa6f3a0
Ldr.Initialized: Yes
--->Ldr.InInitializationOrderModuleList: 000002de3e212440 . 000002de3e27cb90
--->Ldr.InLoadOrderModuleList: 000002de3e2125b0 . 000002de3e27c320
--->Ldr.InMemoryOrderModuleList: 000002de3e2125c0 . 000002de3e27c330
--- --- --- ---
--- --- --- ---
--- --- --- ---
lkd> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
-->+0x010 ImageBaseAddress : Ptr64 Void
-->+0x018 Ldr : Ptr64 _PEB_LDR_DATA
+0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
--- --- --- --- ---
+0x3a0 WaitOnAddressHashTable : [128] Ptr64 Void
+0x7a0 TelemetryCoverageHeader : Ptr64 Void
+0x7a8 CloudFileFlags : Uint4B
再次進入到 WinDbg 輸入 dt _PEB_LDR_DATA
來看一下 Ldr 的數據類型:
lkd> dt _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004 Initialized : UChar
+0x008 SsHandle : Ptr64 Void
-->+0x010 InLoadOrderModuleList : _LIST_ENTRY
-->+0x020 InMemoryOrderModuleList : _LIST_ENTRY
-->+0x030 InInitializationOrderModuleList : _LIST_ENTRY
+0x040 EntryInProgress : Ptr64 Void
+0x048 ShutdownInProgress : UChar
+0x050 ShutdownThreadId : Ptr64 Void
看一下 MSDN 可以知道:
哦!所以 Process 中的 Module 資訊是存在這三個表裡的:
然後儲存著它們訊息的 structure 是 LDR_DATA_TABLE_ENTRY
所以再次進入到 WinDbg 輸入 dt _LDR_DATA_TABLE_ENTRY
來看一下 LDR_DATA_TABLE_ENTRY structure 長什麼樣子:
lkd> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x010 InMemoryOrderLinks : _LIST_ENTRY
+0x020 InInitializationOrderLinks : _LIST_ENTRY
+0x030 DllBase : Ptr64 Void
+0x038 EntryPoint : Ptr64 Void
+0x040 SizeOfImage : Uint4B
+0x048 FullDllName : _UNICODE_STRING
+0x058 BaseDllName : _UNICODE_STRING
+0x068 FlagGroup : [4] UChar
+0x068 Flags : Uint4B
+0x068 PackagedBinary : Pos 0, 1 Bit
+0x068 MarkedForRemoval : Pos 1, 1 Bit
+0x068 ImageDll : Pos 2, 1 Bit
+0x068 LoadNotificationsSent : Pos 3, 1 Bit
+0x068 TelemetryEntryProcessed : Pos 4, 1 Bit
+0x068 ProcessStaticImport : Pos 5, 1 Bit
--- --- --- ---
--- --- --- ---
--- --- --- ---
+0x070 HashLinks : _LIST_ENTRY
--- --- --- ---
--- --- --- ---
--- --- --- ---
所以所以,用一張圖來表達以上資訊:
(如果感覺模糊看不清楚,請複製圖片連結)
(在新分頁打開就可以看高清圖片!)
圖片參考自:33c0c3 大大畫的圖
補充一下:
(因為這是補充的,所以就不詳細寫了)
(多看幾次就會看懂我要寫的內容是什麼 XD)
lkd> dt _PEB 0x000000ec`acd59000
ntdll!_PEB
+0x000 InheritedAddressSpace : 0 ''
+0x001 ReadImageFileExecOptions : 0 ''
--- --- --- ---
--- --- --- ---
--- --- --- ---
+0x003 IsLongPathAwareProcess : 0y0
+0x004 Padding0 : [4] ""
+0x008 Mutant : 0xffffffff`ffffffff Void
+0x010 ImageBaseAddress : 0x00007ff6`7a610000 Void
+0x018 Ldr : 0x00007ff9`baa6f3a0 _PEB_LDR_DATA
--- --- --- ---
--- --- --- ---
--- --- --- ---
lkd> dt 0x00007ff9`baa6f3a0 _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000 Length : 0x58
+0x004 Initialized : 0x1 ''
+0x008 SsHandle : (null)
+0x010 InLoadOrderModuleList : _LIST_ENTRY [ 0x? - 0x? ]
+0x020 InMemoryOrderModuleList : _LIST_ENTRY [ 0x?0 - 0x? ]
+0x030 InInitializationOrderModuleList : _LIST_ENTRY [ 0x? - 0x? ]
+0x040 EntryInProgress : (null)
+0x048 ShutdownInProgress : 0 ''
+0x050 ShutdownThreadId : (null)
lkd> dt 0x00007ff9`baa6f3a0+0x010 _LIST_ENTRY
ntdll!_LIST_ENTRY
[ 0x000002de`3e2125b0 - 0x000002de`3e27c320 ]
+0x000 Flink : 0x? _LIST_ENTRY [ 0x? - 0x? ]
+0x008 Blink : 0x? _LIST_ENTRY [ 0x? - 0x? ]
到了這邊概念大致上已經講完,
接下來講一下 Module 的隱藏方式:
首先,先回到 Blackbone Project 中的 Loader.c 的 BBUnlinkFromLoader Func
PPEB pPeb = PsGetProcessPeb( pProcess );
if (!pPeb)
{
DPRINT( xxxxxxxxxx );
return STATUS_NOT_FOUND;
}
for (PLIST_ENTRY pListEntry = pPeb->Ldr->InLoadOrderModuleList.Flink;
pListEntry != &pPeb->Ldr->InLoadOrderModuleList;
pListEntry = pListEntry->Flink)
{
--- --- ---
--- --- ---
}
xxx pEntry = CONTAINING_RECORD(
pListEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks
);
#define CONTAINING_RECORD(address, type, field) ((type *)( \
(PCHAR)(address) - \
(ULONG_PTR)(&((type *)0)->field)))
// addr: 結構體中某個成員地址
// type: 結構體原本的樣子
// field: 結構體的某個成員
//詳細說明請谷哥...
// Unlink
if ((PVOID)pEntry->DllBase == pBase)
{
RemoveEntryList( &pEntry->InLoadOrderLinks );
RemoveEntryList( &pEntry->InInitializationOrderLinks );
RemoveEntryList( &pEntry->InMemoryOrderLinks );
//RemoveEntryList( &pEntry->HashLinks );
//最後這個 HashLinks 今天沒時間講了,有空再補充上來。
break;
}
FORCEINLINE
BOOLEAN
RemoveEntryList(
_In_ PLIST_ENTRY Entry
)
{
PLIST_ENTRY PrevEntry;
PLIST_ENTRY NextEntry;
NextEntry = Entry->Flink;
PrevEntry = Entry->Blink;
if ((NextEntry->Blink != Entry) || (PrevEntry->Flink != Entry)) {
FatalListEntryError((PVOID)PrevEntry,
(PVOID)Entry,
(PVOID)NextEntry);
}
PrevEntry->Flink = NextEntry;
NextEntry->Blink = PrevEntry;
return (BOOLEAN)(PrevEntry == NextEntry);
}
到這裡,告一段落了!!!!!
不過最後我再補充一項知識,
假設想在 User mode 中做到 PEB 斷鏈有可能嗎?
答案是有的,但是必須想辦法拿到 PEB 的 Address。
我們知道 EProcess 是存在於 Kernel mode,
那要怎麼在 User mode 拿到 PEB 的 Address 呢?
最一開始有說到 PEB 出現在 TEB(Thread Environment Block) 中
TEB(Thread Environment Block):
當 Windows 載入 Process 建立 Thread 時,系統會為每個 Thread 分配 TEB,
且 FS 暫存器會被設置成 FS:0 指向目前 Thread 的 TEB Address,
所以可以拿到 TEB Address。
TEB(Thread Environment Block)結構:
lkd> dt _TEB
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x038 EnvironmentPointer : Ptr64 Void
+0x040 ClientId : _CLIENT_ID
+0x050 ActiveRpcHandle : Ptr64 Void
+0x058 ThreadLocalStoragePointer : Ptr64 Void
-->+0x060 ProcessEnvironmentBlock : Ptr64 _PEB
+0x068 LastErrorValue : Uint4B
+0x06c CountOfOwnedCriticalSections : Uint4B
+0x070 CsrClientThread : Ptr64 Void
--- --- --- ---
--- --- --- ---
--- --- --- ---
--- --- --- ---
--- --- --- ---
--- --- --- ---
看到了吧?有 Process Environment Block 耶!!!
可以再看一下,位於 0x00 的 NtTib 是 _NT_TIB 結構,
_NT_TIB 結構:
lkd> dt _NT_TIB
ntdll!_NT_TIB
+0x000 ExceptionList : Ptr64 _EXCEPTION_REGISTRATION_RECORD
+0x008 StackBase : Ptr64 Void
+0x010 StackLimit : Ptr64 Void
+0x018 SubSystemTib : Ptr64 Void
+0x020 FiberData : Ptr64 Void
+0x020 Version : Uint4B
+0x028 ArbitraryUserPointer : Ptr64 Void
->>+0x030 Self : Ptr64 _NT_TIB
所以呢~所以呢~
直接:
//mov eax,fs:[0x030] //x86 Get PEB
mov eax,gs:[0x060] //x64 Get PEB
//mov ecx,[eax + 0x00c] //x86 PEB 的 Ldr
mov ecx,[eax + 0x018] //x64 PEB 的 Ldr
mov xxx,ecx //把拿到的 Address 放進 xxx 變數
pop ecx
pop eax
好了,這篇真的結束了!
明天將介紹一些方法,來對抗這種 PEB 斷鏈隱藏 Module 的手法!
如果你/妳有發現哪裡寫得不好或是有地方寫錯,
歡迎留個言,大家一起討論討論鴨~~
那我們下期見 o( ̄▽ ̄)ブ